package com.mantru.iotpot.modbus;

import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.webkit.JavascriptInterface;

import com.mantru.iotpot.eventbus.EventMessage;
import com.mantru.iotpot.job.JobMaster;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

//import android.serialport.SerialPort;

import android_serialport_api.SerialPortFinder;
import tp.xmaihh.serialport.SerialHelper;
import tp.xmaihh.serialport.bean.ComBean;
import tp.xmaihh.serialport.stick.AbsStickPackageHelper;
import  com.mantru.iotpot.ApplicationClass;

import org.greenrobot.eventbus.EventBus;

import static android.content.Context.TELEPHONY_SERVICE;

/**
 * Modbus RTU
 * 作者： cmh
 * 日期： 2022/12/13
 */

public class ModbusRtuMaster {
    //协议起始偏移地址
    private static int ProtocolStartOffsetAddress = 0;
    //主窗体Context对象
    public ApplicationClass ac;
    public Context parent;
    //使用serialport第三方库
    public SerialHelper serialHelper;
    //排队发送线程
    public ModbusSendThread sender;
    //最后读取的地址、读取长度
    public int LastAddress = 0, LastLength = 0;
    //设备id
    public String DeviceID = "aaaa";
    //发送1个包和收到回复包的序号，从1开始，自增
    public long SequenceNo = 0;
    //几个串口收发时间变量
    private long com_receive_last_time = 0;  //串口最后一次收到数据的时间截，单位：ms
    public long com_send_last_time = 0;     //串口最后一次发送数据的时间截，单位：ms
    public int  com_wait_receive_count = 0; //向串口发送了指令的数量，当串口回复的时候这里会减1
    private String com_receive_data = "";    //串口最大一个包收256个字节，叠包的情况这里做缓存


    public ModbusRtuMaster(Context aParent) {
        parent = aParent;
        ac = (ApplicationClass)parent;
        //Log("全部串口-->" + GetCOMList());
        //初始化SerialHelper对象，设定串口名称和波特率（115200）
        int iBaudRate = 115200;
        serialHelper = new SerialHelper("/dev/ttyS3", iBaudRate) {
            @Override
            protected void onDataReceived(ComBean comBean) {
                if (ac.app_is_release == true) {
                    Log("app_is_release=" + ac.app_is_release);
                    serialHelper.close();
                    return;
                }

                //根据自己的业务自行处理接收的数据
                com_receive_last_time = Common.GetTimeStamp13();
                com_wait_receive_count--;
                if (com_receive_last_time - com_send_last_time < 200)
                    com_wait_receive_count = 0;
                String receive_data = ByteUtil.toHexString(comBean.bRec);
                String decode_str = Decode_ReceiveBuffer(receive_data);
                if (decode_str.equals("error")) {
                    receive_data = "";
                    com_receive_data = "";
                    return;
                }

                if (decode_str.length() <= 0)
                {
                    //串口最大一个包收256个字节，叠包的情况这里做缓存
                    com_receive_data += " " + receive_data.trim();
                    decode_str = Decode_ReceiveBuffer(com_receive_data);
                    if (decode_str.equals("error")) {
                        receive_data = "";
                        com_receive_data = "";
                        return;
                    }
                    if (decode_str.length() == 0) {
                        if (com_receive_data.trim().startsWith("01") == false) {
                            Log("com_receive_data error1=" + com_receive_data);
                            com_receive_data = "";

                        }
                        if (com_receive_data.length() > 1000) {
                            Log("com_receive_data error2=" + com_receive_data);
                            com_receive_data = "";
                        }
                        return;
                    }
                    receive_data = com_receive_data.trim();
                    com_receive_data = "";

                }
                Log("收到串口数据：SequenceNo=" + String.valueOf(SequenceNo) + "，Bytes=" + receive_data + decode_str);
                receive_data = receive_data.replace(" ", "");
                //2023.04.13 对粘包的情况进行判断
                if (decode_str.length() > 0) {

                    ac.OnComData(receive_data, LastAddress, LastLength);
                }
            }
        };

        /*
         * 默认的BaseStickPackageHelper将接收的数据扩展成64位，一般用不到这么多位
         * 我这里重新设定一个自适应数据位数的
         */
        serialHelper.setStickPackageHelper(new AbsStickPackageHelper() {
            @Override
            public byte[] execute(InputStream is) {
                try {
                    int available = is.available();

                    if (available > 0) {
                        byte[] buffer = new byte[available];
                        int size = is.read(buffer);
                        //String receive_data = ByteUtil.toHexString(buffer);
                        //Log("available=" + available + ",size=" + size + ",SequenceNo=" + SequenceNo + ",data=" + receive_data);
                        if (size > 0) {
                            return buffer;
                        }
                    } else {
                        SystemClock.sleep(10);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
        try {
            serialHelper.open();
        }catch (Exception ex){
            Log("打开串口出错：" + ex.getMessage());
            //弹出故障专用界面
            String msg = "{\"error_code\":\"COM_OPEN_ERROR\",\"error_desc\":\"打开串口失败，请断电重启设备\",\"error_data\":\"\"}";
            EventMessage e = new EventMessage(EventMessage.MSG_ID_ErrorInfo, msg);
            EventBus.getDefault().post(e);
        }
        //创建排队发送线程
        sender = new ModbusSendThread(this);
        sender.start();
    }

    public void Close()
    {
        try {
            serialHelper.close();
        }catch (Exception ex){
            Log("关闭串口出错：" + ex.getMessage());
        }
    }

    public void Log(String value)
    {
        /*
        if (handler != null) {
            Message msg = new Message();
            msg.what = 1;    //MsgID_OnShowComData
            msg.obj = value;
            handler.sendMessage(msg);
        }
        */
        System.out.println("-->" + value);

        //无设备SN码或网络断线的情况不往服务器端保存日志
        if (DeviceID.length() <= 0 || ac.net_work_status != 1)
            return;

        new Thread() {
            @Override
            public void run() {
                int error_code = 0;      //0表示没有发生异异，1表示有异常
                try
                {
                    String api_url = Common.API_Server_Url + "?txt_type=/pot/save_log/&device_id=" + DeviceID + "&code=200&timestamp=" + Common.GetTimeStamp13() + "&data=" + URLEncoder.encode(value);
                    URL url = new URL(api_url);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    InputStream is = conn.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                    StringBuilder builder = new StringBuilder();
                    String line = "";
                    while ((line = reader.readLine()) != null) {
                        builder.append(line);
                    }
                    is.close();
                    conn.disconnect();
                }
                catch(Exception ex)
                {
                    error_code = 1;
                    //ac.net_work_status = 0;    //网络状态断线

                    System.out.println("log-->" + ex.getMessage());
                }
            }
        }.start();
    }

    /**
     * 组装Modbus RTU消息帧
     * @param slave 从站地址号
     * @param function_code 功能码
     * @param starting_address 读取寄存器起始地址 / 写入寄存器地址 / 写入寄存器起始地址
     * @param quantity_of_x 读取寄存器个数 / 写入寄存器个数
     * @param output_value 需要写入单个寄存器的数值
     * @param output_values 需要写入多个寄存器的数组
     * @return 将整个消息帧转成byte[]
     * @throws ModbusError Modbus错误
     */
    synchronized private byte[] execute(int slave, int function_code, int starting_address, int quantity_of_x, int output_value, int[] output_values) throws ModbusError {
        //检查参数是否符合协议规定
        if (slave < 0 || slave > 0xff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid slave " + slave);
        }
        if (starting_address < 0 || starting_address > 0xffff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid starting_address " + starting_address);
        }
        if (quantity_of_x < 1 || quantity_of_x > 0xff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid quantity_of_x " + quantity_of_x);
        }

        //LastAddress = starting_address;
        //LastLength = quantity_of_x;
        //计算偏移地址
        starting_address += ProtocolStartOffsetAddress;

        // 构造request
        ByteArrayWriter request = new ByteArrayWriter();
        //写入从站地址号
        request.writeInt8(slave);
        //根据功能码组装数据区
        //如果为读取寄存器指令
        if (function_code == ModbusFunction.READ_COILS || function_code == ModbusFunction.READ_DISCRETE_INPUTS || function_code == ModbusFunction.READ_INPUT_REGISTERS || function_code == ModbusFunction.READ_HOLDING_REGISTERS) {
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);

        } else if (function_code == ModbusFunction.WRITE_SINGLE_COIL || function_code == ModbusFunction.WRITE_SINGLE_REGISTER) {//写单个寄存器指令
            if (function_code == ModbusFunction.WRITE_SINGLE_COIL)
                if (output_value != 0) output_value = 0xff00;//如果为线圈寄存器（写1时为 FF 00,写0时为00 00）
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(output_value);

        } else if (function_code == ModbusFunction.WRITE_COILS) {//写多个线圈寄存器
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);

            //计算写入字节数
            int writeByteCount = (quantity_of_x / 8) + 1;/// 满足关系-> (w /8) + 1
            //写入数量 == 8 ,则写入字节数为1
            if (quantity_of_x % 8 == 0) {
                writeByteCount -= 1;
            }
            request.writeInt8(writeByteCount);

            int index = 0;
            //如果写入数据数量 > 8 ，则需要拆分开来
            int start = 0;//数组开始位置
            int end = 7;//数组结束位置
            int[] splitData = new int[8];
            //循环写入拆分数组，直到剩下最后一组 元素个数 <= 8 的数据
            while (writeByteCount > 1) {
                writeByteCount--;
                int sIndex = 0;
                for (index = start; index <= end; index++){
                    splitData [sIndex++] = output_values[index];
                }
                //数据反转 对于是否要反转要看你传过来的数据，如果高低位顺序正确则不用反转
                splitData = reverseArr(splitData);
                //写入拆分数组
                request.writeInt8(toDecimal(splitData));
                start = index;
                end += 8;
            }
            //写入最后剩下的数据
            int last = quantity_of_x - index;
            int[] tData = new int[last];
            System.arraycopy(output_values, index, tData, 0, last);
            //数据反转 对于是否要反转要看你传过来的数据，如果高低位顺序正确则不用反转
            tData = reverseArr(tData);
            request.writeInt8(toDecimal(tData));
        } else if (function_code == ModbusFunction.WRITE_HOLDING_REGISTERS) {//写多个保持寄存器
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);
            request.writeInt8(2 * quantity_of_x);
            //写入数据
            for (int v : output_values) {
                request.writeInt16(v);
            }
        } else {
            throw new ModbusError(ModbusErrorType.ModbusFunctionNotSupportedError, "Not support function " + function_code);
        }
        byte[] bytes = request.toByteArray();
        //计算CRC校验码
        int crc = CRC16.compute(bytes);
        request.writeInt16Reversal(crc);
        bytes = request.toByteArray();
        return bytes;
    }

    /**
     * 读多个线圈寄存器
     * @param slave 从站地址
     * @param startAddress 起始地址
     * @param numberOfPoints 读取线圈寄存器个数
     * @throws ModbusError Modbus错误
     */
    public void readCoils(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.READ_COILS, startAddress, numberOfPoints, 0, null);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, startAddress, numberOfPoints);
    }
    //读单个线圈寄存器
    public void readCoil(int slave, int address) throws ModbusError {
        readCoils(slave, address, 1);
    }

    /**
     * 读多个保持寄存器
     * @param slave 从站地址
     * @param startAddress 起始地址
     * @param numberOfPoints 读取保持寄存器个数
     * @throws ModbusError Modbus错误
     */
    private void readHoldingRegisters(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.READ_HOLDING_REGISTERS, startAddress, numberOfPoints, 0, null);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, startAddress, numberOfPoints);
    }
    //读单个保持寄存器
    private void readHoldingRegister(int slave, int address) throws ModbusError {
        readHoldingRegisters(slave, address, 1);
    }
    //改进的方法
    public boolean ReadHoldingRegister(int slave, int startAddress, int numberOfPoints){
        try
        {
            readHoldingRegisters(slave, startAddress, numberOfPoints);
            //2023.04.08 判断向串口发指令无回复的情况
            long now = Common.GetTimeStamp13();
            long sub_time = now - com_receive_last_time;
            if (com_receive_last_time > 0 && com_wait_receive_count >= 2 && sub_time >= 3000){
                String log_data = "，读," + com_wait_receive_count + "," + sub_time;
                com_wait_receive_count = 0;
                com_receive_last_time = now;
                String error_code = "E71";
                String error_type = "串口故障";
                String error_desc = "下位机主板无响应";  // + log_data;
                error_desc = error_type + "，" + error_desc + "，请断电重启设备";

                if (ac.error_code.equals(error_code) == false) {
                    String msg = "{\"error_code\":\"" + error_code + "\",\"error_desc\":\"" + error_desc + "\",\"error_type\":\"" + error_type + "\"}";
                    EventMessage e = new EventMessage(EventMessage.MSG_ID_ErrorInfo, msg);
                    EventBus.getDefault().post(e);

                    ac.dao.SaveErrorCode("", error_code, error_type, error_desc, "");
                    ac.PutError(error_code, error_type, error_desc);

                    ac.error_code = error_code;
                    ac.error_desc = error_desc;
                    ac.error_type = error_type;
                }
            }
            return true;
        }catch (Exception ex)
        {
            Log("读保持寄存器出错：address=" + startAddress + ",len=" + numberOfPoints + ",error=" + ex.getMessage());
            return false;
        }
    }


    /**
     * 读多个输入寄存器
     * @param slave 从站地址
     * @param startAddress 起始地址
     * @param numberOfPoints 读取输入寄存器个数
     * @throws ModbusError Modbus错误
     */
    public void readInputRegisters(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.READ_INPUT_REGISTERS, startAddress, numberOfPoints, 0, null);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, startAddress, numberOfPoints);
    }
    //读单个输入寄存器
    public void readInputRegister(int slave, int address) throws ModbusError {
        readInputRegisters(slave, address, 1);
    }

    /**
     * 读多个离散输入寄存器
     * @param slave 从站地址
     * @param startAddress 起始地址
     * @param numberOfPoints 读取离散输入寄存器个数
     * @throws ModbusError Modbus错误
     */
    public void readDiscreteInputs(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.READ_DISCRETE_INPUTS, startAddress, numberOfPoints, 0, null);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, startAddress, numberOfPoints);
    }
    //读单个离散输入寄存器
    public void readDiscreteInput(int slave, int address) throws ModbusError {
        readDiscreteInputs(slave, address, 1);
    }

    /**
     * 写单个线圈寄存器
     * @param slave 从站地址
     * @param address 写入寄存器地址
     * @param value 写入值（true/false)
     * @throws ModbusError Modbus错误
     */
    public void writeSingleCoil(int slave, int address, boolean value) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_SINGLE_COIL, address, 1, value ? 1 : 0, null);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, address, 1);
    }

    /**
     * 写单个保持寄存器
     * @param slave 从站地址
     * @param address 写入寄存器地址
     * @param value 写入值
     * @throws ModbusError Modbus错误
     */
    public void writeSingleRegister(int slave, int address, int value, JobMaster job) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_SINGLE_REGISTER, address, 1, value, null);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        if (job != null){
            //档位，0-9档
            if (address == 0x0015) job.fire_value = value;
            //锅转向，1逆时针、2顺时针（协议值：0是顺时针、1是逆时针）
            if (address == 0x0011)  job.rotation_value = value;
            //转速，0停、1慢、2中、3快
            if (address == 0x0010) job.speed_value = value;
        }
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, address, 1);

        //2023.04.08 判断向串口发指令无回复的情况
        long now = Common.GetTimeStamp13();
        long sub_time = now - com_receive_last_time;
        if (com_receive_last_time > 0 && com_wait_receive_count >= 2 && sub_time >= 3000){
            String log_data = "，写," + com_wait_receive_count + "," + sub_time;
            com_wait_receive_count = 0;
            com_receive_last_time = now;
            String error_code = "FFFF";
            String error_type = "串口故障";
            String error_desc = "串口主板无响应" + log_data;
            error_desc = error_type + "，" + error_desc + "，请断电重启设备";

            String msg = "{\"error_code\":\""+error_code+"\",\"error_desc\":\""+error_desc+"\",\"error_data\":\"\"}";
            EventMessage e = new EventMessage(EventMessage.MSG_ID_ErrorInfo, msg);
            EventBus.getDefault().post(e);

        }
    }

    /**
     *   写入多个保持寄存器
     * @param slave 从站地址
     * @param address 写入寄存器地址
     * @param sCount 写入寄存器个数
     * @param data 写入数据
     * @throws ModbusError
     */
    public void writeHoldingRegisters(int slave, int address, int sCount, int [] data) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_HOLDING_REGISTERS, address, sCount, 0, data);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, address, sCount);
    }

    /**
     *   写入多个位
     * @param slave 从站地址
     * @param address 写入寄存器地址
     * @param bCount 写入寄存器个数
     * @param data 写入数据{1,0}
     * @throws ModbusError
     */
    public void writeCoils(int slave, int address,int bCount, int [] data) throws ModbusError {
        com_send_last_time = Common.GetTimeStamp13();
        com_wait_receive_count++;
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_COILS, address, bCount, 0, data);
        //SequenceNo++;
        //Log("串口发送：SequenceNo=" + SequenceNo + "，Bytes=" + ByteUtil.toHexString(sendBytes) + Decode_SendBuffer(ByteUtil.toHexString(sendBytes)));
        //this.serialHelper.send(sendBytes);
        sender.AddSendData(sendBytes, address, bCount);
    }



    //将数组反转
    private int[] reverseArr(int[] arr) {
        int[] tem = new int[arr.length];
        for(int i=0; i<arr.length; i++) {
            tem[i] = arr[arr.length-1-i];
        }
        return tem;
    }

    //将int[1,0,0,1,1,0]数组转换为十进制数据
    private int toDecimal(int[] data){
        int result = 0;
        if(data != null){
            StringBuilder sData = new StringBuilder();
            for (int d : data){
                sData.append(d);
            }
            try {
                result = Integer.parseInt(sData.toString(), 2);
            } catch (NumberFormatException e) {
                result = -1;
            }

        }
        return result;
    }

    //对发送的内容进行中文转译
    //读取send_data=01 03 01 69 00 07 d5 e8
    //写send_data=01 06 01 40 00 00 89 e2
    public String Decode_SendBuffer(String send_data) {
        String return_data = "";
        //针对IAP升级的包进行处理
        if (ac.iap_status == 1)
        {
            return "（IAP升级写入包）";
        }
        send_data = send_data.replace(" ", "");
        String function_code = send_data.substring(2, 4);
        String registers_address = send_data.substring(4, 8);
        String output_value = send_data.substring(8, 12);
        if (function_code.equals("03"))
            return_data = "（读取原始寄存器=0x" + Decode_RegistersAddress(registers_address) + "，数量=" + Integer.parseInt(output_value,16) + "）";
        if (function_code.equals("06")) {
            String address = Decode_RegistersAddress(registers_address);
            int value = Integer.parseInt(output_value, 16);
            String desc = "";
            //判断4大控制地址
            if (address.equals("0010")) desc = "，转速" + value;
            if (address.equals("0011")) desc = "，转向" + value;
            if (address.equals("0013")) desc = "，锅位置" + value;
            if (address.equals("0015")) desc = "，档位" + value;

            return_data = "（写入原始寄存器0x" + address + "，值=" + value + desc + "）";
        }
        if (function_code.equals("10")) {
            String address = Decode_RegistersAddress(registers_address);
            return_data = "（写入多个寄存器0x" + address + "）";
        }
        return return_data;
    }

    //对收到的内容进行中文转译
    //读取回复receive_data=01 03 字节长度 数据1 数据2 ... CRC16
    //写入回复receive_data=01 06 01 48 00 00 08 20     06就是回复返回原指令
    private String Decode_ReceiveBuffer(String receive_data) {
        String return_data = "";
        try {
            receive_data = receive_data.replace(" ", "");

            //针对IAP升级的回复包进行处理
            if (ac.iap_status == 1 || receive_data.length() == 2) {
                return "（IAP升级应答包）";
            }

            String begin_code = receive_data.substring(0, 2);
            String function_code = receive_data.substring(2, 4);

            if (begin_code.equals("01")) {
                if (function_code.equals("03")) {
                    int len = Integer.parseInt(receive_data.substring(4, 6), 16);
                    if (receive_data.length() >= len * 2 + 10) {
                        if (receive_data.length() > len * 2 + 10) {
                            return_data = "error";
                        } else {
                            String data = receive_data.substring(6, 6 + len * 2);
                            return_data = "（读取回复数据长度=" + len + "，数据=" + data + "）";
                            //2025.05.17  收到的数据进行CRC检验
                            boolean crc_result = CheckCRCIsOK(receive_data);
                            if (crc_result == false) {
                                ac.SaveLog("CRC校验出错：" + receive_data);
                                return_data = "error";
                            }

                        }
                    }
                }
                if (function_code.equals("06")) {
                    String registers_address = receive_data.substring(4, 8);
                    String input_value = receive_data.substring(8, 12);
                    return_data = "（写入原始寄存器0x" + Decode_RegistersAddress(registers_address) + "，值=" + Integer.parseInt(input_value, 16) + "）";
                }
                if (function_code.equals("10")) {
                    String registers_address = receive_data.substring(4, 8);
                    return_data = "（写入多个寄存器0x" + Decode_RegistersAddress(registers_address) + "）";
                }
            }
        }
        catch(Exception ex)
        {
            Log("ModbusRtuMaster.Decode_ReceiveBuffer出错：" + ex.getMessage());
        }
        return return_data;
    }

    //将协议起始偏移地址还原为原始地址
    private String Decode_RegistersAddress(String hex_address){
        int registers_address = Integer.parseInt(hex_address,16);
        if (registers_address > ProtocolStartOffsetAddress)
            registers_address = registers_address - ProtocolStartOffsetAddress;
        hex_address = Integer.toHexString(registers_address).toUpperCase();
        if (hex_address.length() == 1)
            hex_address = "000" + hex_address;
        if (hex_address.length() == 2)
            hex_address = "00" + hex_address;
        if (hex_address.length() == 3)
            hex_address = "0" + hex_address;
        return hex_address;
    }

    //译出故障码的中文描述
    public String Decode_ErrorCode(String code)
    {
        code = code.toUpperCase();
        String return_value = "";
        //机芯故障
        if (code.equals("0010")) return_value = "IGBT模块短路、过流";
        if (code.equals("0011")) return_value = "调频峰值电流过流";
        if (code.equals("0012")) return_value = "没有高频反馈信号";
        if (code.equals("0013")) return_value = "高频信号线反相(启动时脉宽大于设定值)";
        if (code.equals("0014")) return_value = "";
        if (code.equals("0015")) return_value = "";
        if (code.equals("0016")) return_value = "";
        if (code.equals("0018")) return_value = "";

        if (code.equals("0020")) return_value = "低频遇压传感器没有连接";
        if (code.equals("0021")) return_value = "市电电压过低(低于185V出现故障代码)";
        if (code.equals("0022")) return_value = "市电电压过高(高于274V出现故障代码)";
        if (code.equals("0023")) return_value = "低频电流传感器没有连接";
        if (code.equals("0024")) return_value = "市电电流过高(高于42A)";
        if (code.equals("0025")) return_value = "";

        if (code.equals("0030")) return_value = "机芯散热片温度传感器没有连接";
        if (code.equals("0031")) return_value = "机芯散热片温度传感器短路";
        if (code.equals("0032")) return_value = "机芯散热片温度传感器高温(高于79度出现故障代码)";
        if (code.equals("0033")) return_value = "锅底传感器开路";
        if (code.equals("0034")) return_value = "锅底传感器短路";
        if (code.equals("0035")) return_value = "锅底传感器高温";
        if (code.equals("0039")) return_value = "";

        if (code.equals("0040")) return_value = "线盘温度传感器没有连接";
        if (code.equals("0041")) return_value = "线盘温度传感器短路";
        if (code.equals("0042")) return_value = "线盘温度传感器高温";
        if (code.equals("0046")) return_value = "";
        if (code.equals("0047")) return_value = "";
        if (code.equals("0048")) return_value = "";
        if (code.equals("0049")) return_value = "";
        if (code.equals("004A")) return_value = "";
        if (code.equals("004B")) return_value = "干烧保护";

        if (code.equals("0052")) return_value = "线盘风机故障";
        if (code.equals("0053")) return_value = "机芯风机故障";

        if (code.equals("0060")) return_value = "EEPROM芯片通信异常";
        if (code.equals("0070")) return_value = "机芯通讯失败";
        if (code.equals("0072")) return_value = "驱动器通讯失败";
        if (code.equals("0073")) return_value = "驱动器故障";


        return return_value;
    }

    //译出故障码的故障类型
    public String Decode_ErrorType(String code)
    {
        code = code.toUpperCase();
        String return_value = "机芯故障";

        //电机故障(位置/转锅)
        if (code.equals("0001")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0002")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0003")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0004")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0005")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0006")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0007")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0008")) return_value = "电机故障(位置/转锅)";
        if (code.equals("0009")) return_value = "电机故障(位置/转锅)";
        if (code.equals("000A")) return_value = "电机故障(位置/转锅)";
        if (code.equals("000B")) return_value = "电机故障(位置/转锅)";

        return return_value;
    }

    //从串口读取返回的16进制字符串里提取指定地址的值
    //read_start_address开始地址
    //get_address要读取的地址
    //len要读取的字节数
    //data=01031400500001001e00780014000a000f005500000000d1d7
    public long Decode_GetValue(String return_data, int read_start_address, int get_address, int len) {
        int begin_index = 6 + (get_address - read_start_address) * 4;
        int end_index = begin_index + len * 2;
        String value_str = return_data.substring(begin_index, end_index);
        return Common.hex2int(value_str);
    }
    public String Decode_GetValue_Hex(String return_data, int read_start_address, int get_address, int len) {
        int begin_index = 6 + (get_address - read_start_address) * 4;
        int end_index = begin_index + len * 2;
        String value_str = return_data.substring(begin_index, end_index);
        return value_str;
    }

    //软件版本号转译
    //0x0096=150，版本号是V1.5.0
    public String Decode_Version(String hex) {
        int v = Integer.parseInt(hex, 16);
        String version = String.valueOf(v);
        if (version.length() >= 3)
        {
            int v1 = v / 100;
            v = v - v1 * 100;
            int v2 = v / 10;
            int v3 = v - v2 * 10;
            version = String.valueOf(v1) + "." + String.valueOf(v2) + "." + String.valueOf(v3);
        }
        version = "V" + version;
        return version;
    }

    //判断串口是否可以发信息
    public boolean CheckIsCanSend()
    {
        //串口发送200ms内无回复的情况视为等待回复中，不可以继续发消息
        if (com_wait_receive_count > 0 && com_send_last_time - com_receive_last_time < 200)
            return false;
        return true;
    }

    //检查串口是不是有发无回复超过3秒钟，2024.07.17增加
    public boolean CheckIsE71()
    {
        //串口发送5000ms内无回复的情况视为故障
        long now = Common.GetTimeStamp13();
        if (now - com_send_last_time < 1000 && com_wait_receive_count > 0 && com_send_last_time - com_receive_last_time >= 5000) {
            try {
                String msg = "{\"error_code\":\"E71\",\"error_desc\":\"上位机通讯失败\",\"error_data\":\"\"}";
                EventMessage e = new EventMessage(EventMessage.MSG_ID_ErrorInfo, msg);
                EventBus.getDefault().post(e);

            }
            catch (Exception ex){

            }
            return true;
        }
        return false;
    }


    //获取硬件设备全部串口号/串口地址（COM口）
    private String GetCOMList()
    {
        String str_value = "";
        try
        {
            //获取所有串口名字
            //ttyXRUSB3 (xr_usb_serial),ttyXRUSB2 (xr_usb_serial),ttyXRUSB1 (xr_usb_serial),ttyXRUSB0 (xr_usb_serial),ttyS0 (serial),ttyS4 (serial),ttyFIQ0 (fiq-debugger)
            String[] devices = new SerialPortFinder().getAllDevices();
            //获取所用串口地址
            //目前这块主板的全部串口地址  /dev/ttyXRUSB3,/dev/ttyXRUSB2,/dev/ttyXRUSB1,/dev/ttyXRUSB0,/dev/ttyS0,/dev/ttyS4,/dev/ttyFIQ0
            String[] devicesPath = new SerialPortFinder().getAllDevicesPath();
            for (int i=0; i<devicesPath.length; i++)
            {
                if (str_value.length() > 0)
                    str_value += ",";
                str_value += devicesPath[i].trim();
            }
        }
        catch(Exception ex)
        {}
        return str_value;
    }

    //16进制字符串转10进制数组
    private byte[] hex2bytes(String hex_str) {
        byte[] bytes = new byte[hex_str.length() / 2];
        for (int i = 0; i < hex_str.length(); i += 2) {
            bytes[i/2] = (byte) (
                    (Character.digit(hex_str.charAt(i), 16) << 4)
                            | Character.digit(hex_str.charAt(i+1), 16)
            );
        }
        return bytes;
    }

    //计算收到数据的CRC校验码是否正确，返回true表示正确
    private boolean CheckCRCIsOK(String receive_data) {
        byte[] temp_buffer1 = hex2bytes(receive_data);
        byte[] temp_buffer2 = new byte[temp_buffer1.length - 2];
        System.arraycopy(temp_buffer1, 0, temp_buffer2, 0, temp_buffer2.length);
        int crc = CRC16.compute(temp_buffer2);
        ByteArrayWriter request = new ByteArrayWriter();
        request.writeInt16Reversal(crc);
        byte[] temp_buffer3 = request.toByteArray();
        boolean crc_result = false;
        if (temp_buffer1[temp_buffer1.length - 2] == temp_buffer3[0] && temp_buffer1[temp_buffer1.length - 1] == temp_buffer3[1])
            crc_result = true;
        if (temp_buffer1[temp_buffer1.length - 2] == temp_buffer3[1] && temp_buffer1[temp_buffer1.length - 1] == temp_buffer3[0])
            crc_result = true;
        temp_buffer1 = null;
        temp_buffer2 = null;
        temp_buffer3 = null;
        try {
            request.close();
        } catch (Exception ex) {}
        request = null;
        return crc_result;
    }

}


